package com.pb.infra.oth.util;

import lombok.extern.slf4j.Slf4j;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日期工具类
 *
 * @Author:jinyang
 * @Date: 2019/8/8
 * @Time: 15:23
 */
@Slf4j
public class DateTimeUtil {
    private DateTimeUtil() {
        throw new IllegalStateException("Utility class");
    }

    private static String templates[] = {"yyyy-MM-dd", "yyyy-MM-d", "yyyy-M-dd", "yyyy-M-d", "yyyyMMdd", "yyyyMMd", "yyyyMdd", "yyyyMd", "yyyy年MM月dd日", "yyyy年MM月d日", "yyyy年M月dd日", "yyyy年M月d日", "yyyy/MM/dd", "yyyy/MM/d", "yyyy/M/dd", "yyyy/M/d", "yyyy.MM.dd", "yyyy.MM.d", "yyyy.M.dd", "yyyy.M.d"};

    public static String matchDate(String date, String pattern) {
        if (StringUtil.isEmpty(date)) {
            return "";
        }
        Date parse = null;
        boolean isFlag = false;
        for (int i = 0, size = templates.length; i < size; i++) {
            String templatePattern = templates[i];
            try {
                SimpleDateFormat format = new SimpleDateFormat(templatePattern);
                parse = format.parse(date);
            } catch (Exception e) {
                continue;
            }
            isFlag = true;
            break;
        }
        if (isFlag) {
            SimpleDateFormat formatRes = new SimpleDateFormat(pattern);
            return formatRes.format(parse);
        } else {

            return null;
        }
    }

    /**
     * Date转化为String
     *
     * @param date   Date对象
     * @param format 格式化字符串
     * @return String 格式化后的日期字符串
     */
    public static String getStrFromDate(Date date, String format) {
        return new SimpleDateFormat(format).format(date);
    }

    public static String getStrFromNewDate() {
        return new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date());
    }

    public static String getNewData(Date date) {
        return new SimpleDateFormat("yyyy/MM/dd").format(date);
    }

    public static String getDate() {
        return new SimpleDateFormat("yyyyMMdd").format(new Date());
    }

    public static Date getStrNewData(String date) {
        Date date1 = null;
        try {
            date1 =  new SimpleDateFormat("yyyy/MM/dd").parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date1;
    }

    public static Date getDate(String date) {
        Date date1 = null;
        try {
            date1 =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date1;
    }
    /**
     * 判断一个字符串是否是日期格式：2015-12-31,2015/12/31,20151231
     *
     * @param date 日期字符串
     * @return boolean    是日期格式：true，否则：false
     */
    public static boolean isDate(String date) {
        String rexp = "^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))";
        Pattern pat = Pattern.compile(rexp);
        Matcher mat = pat.matcher(date);
        return mat.matches();
    }

    /**
     * 获取当前时间戳，单位:秒
     *
     * @return
     */
    public static long currentSecond() {
        return System.currentTimeMillis() / 1000L;
    }


    /**
     * 时间类型转换
     */
    public static String getTime(String time) throws ParseException {
        String oldDate = time.replace("Z", " UTC");
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS Z");
        Date date = df.parse(oldDate);
        SimpleDateFormat df1 = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK);
        Date date1 = df1.parse(date.toString());
        DateFormat df2 = new SimpleDateFormat("yyyyMMdd");
        return df2.format(date1);
    }

    public static String getAddTime(int day) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy/MM/dd");
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH,  day);
        return sf.format(c.getTime());
    }


    public static String getAddDate(String time,int day) throws Exception{
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
        Calendar c = Calendar.getInstance();
        Date date=sf.parse(time);
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH,  day);
        return sf.format(c.getTime());
    }



    public static String getDayBefore(String date) throws ParseException {
        try {
            DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            Date end = dateFormat.parse(date);
            Calendar sd = Calendar.getInstance();
            sd.setTime(end);
            sd.add(Calendar.DATE,+1);
            return dateFormat.format(sd.getTime());
        }catch (ParseException e){
            e.printStackTrace();
        }
        return null;
    }

    public static String getDayLast(String date)  {
        try {
            DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
            Date end = dateFormat.parse(date);
            Calendar sd = Calendar.getInstance();
            sd.setTime(end);
            sd.add(Calendar.DATE,-1);
            return dateFormat.format(sd.getTime());
        }catch (ParseException e){
            e.printStackTrace();
            return null;
        }
    }

    //获取两个日期之间间隔的所有日期
    public static List<String> betweenDays(String statTime, String endTime) {
        List<String> days = new ArrayList<String>();
        DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        try {
            Date start = dateFormat.parse(statTime);
            Date end = dateFormat.parse(endTime);
            Calendar tempStart = Calendar.getInstance();
            tempStart.setTime(start);

            Calendar tempEnd = Calendar.getInstance();
            tempEnd.setTime(end);

            tempEnd.add(Calendar.DATE, +1);

            while (tempStart.before(tempEnd)) {
                days.add(dateFormat.format(tempStart.getTime()));
                tempStart.add(Calendar.DAY_OF_YEAR, 1);
            }

        } catch (ParseException e) {
            e.printStackTrace();
        }
        return days;
    }

    /**
     * String 转 Date
     * @param str
     * @param sdf
     * @return
     */
    public static Date getStringToDate(String str, SimpleDateFormat sdf) {
        if (StringUtil.isEmpty(str)) {
            return null;
        }
        if (StringUtil.isEmpty(sdf)) {
            throw new NullPointerException("时间格式器为空！SimpleDateFormat is null!");
        }
        Date date = null;
        try {
            date = sdf.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
    /**
     * 获得给定日期之后或之前（days为负数）days天的日期 如果参数为null，则抛出NullPointerException
     *
     * @param date
     * @param days
     * @return Date
     */
    public static Date getNextDatesByDate(Date date, int days) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.add(Calendar.DATE, days);
        return cal.getTime();
    }
    /**
     * 判断两个日期是否同一月
     * @author 沈星浩
     * @date 2020年5月20日
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameMonth(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return false;
        }
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
        return (cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH));
    }
    /**
     * 判断给定日期是否是当月的第一天
     */
    public static boolean isFirstDayOfMonth(Date date) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        if (cal.get(Calendar.DATE) == 1) {
            return true;
        }
        return false;
    }
    /**
     * 判断两个日期是否同一天
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameDay(Date date1, Date date2) {
        if (date1 == null || date2 == null) {
            return false;
        }
        GregorianCalendar cal1 = new GregorianCalendar();
        cal1.setTime(date1);
        GregorianCalendar cal2 = new GregorianCalendar();
        cal2.setTime(date2);
        return (cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH) && cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH));
    }
    /**
     * 获得给定日期之间的月数
     * @author 沈星浩
     * @date 2020年5月21日
     * @param monthCalcFirstDay
     * @param monthCalcLastDay
     * @return
     */
    public static int getMonthsBetWeenDays(Date monthCalcFirstDay, Date monthCalcLastDay) {
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(monthCalcFirstDay);
        c2.setTime(monthCalcLastDay);
        int year = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);
        return year * 12 + c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH);
    }
    /**
     * 获得给定日期当年的第一天 如果参数为null，则抛出NullPointerException
     * @author
     * @date 2022/9/11
     */
    public static Date getFirstDayOfYearDate(Date date) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, 1);
        cal.set(Calendar.MONTH, 0);
        return cal.getTime();
    }
    /**
     * 输入年份，不管是不是字符串，都转换为整型
     * @param <T> 类型
     * @param year 年份
     * @return year 整型年份
     */
    private static<T> int getYear(T year){
        int yy = 0;
        try{
            yy = Integer.parseInt(year.toString());
        }catch(NumberFormatException e){
            throw new NumberFormatException("年份类型转换失败，请传入4位数字组成的整型或者字符串");
        }
        return yy;
    }
    /**
     * 输入月份，不管是不是字符串，都转换为整型
     * @param <T> 类型
     * @param month 月份
     * @return month 整型月份
     */
    private static<T> int getMonth(T month){
        int mm = 0;
        try{
            mm = Integer.parseInt(month.toString());
        }catch(NumberFormatException e){
            throw new NumberFormatException("月份类型转换失败，请传入2位数字组成的整型或者字符串");
        }
        return mm;
    }
    /**
     * 由java.util.Date到java.sql.Date的类型转换
     * @param date java.util.Date
     * @return Date java.sql.Date
     */
    public static Date getSqlDate(java.util.Date date){
        return new Date(date.getTime());
    }

    /**
     * 获得某年某月第一天的日期
     * @param year	年，可以为String或者int类型的
     * @param month	月，可以为String或者int类型的
     * @return Date	java.util.Date
     */
    public static<T,E> Date getFirstDayOfMonth(T year,E month){
        int yy = getYear(year);
        int mm = getMonth(month);
        Calendar calendar=Calendar.getInstance();
        calendar.set(Calendar.YEAR,yy);
        calendar.set(Calendar.MONTH,mm-1);
        calendar.set(Calendar.DATE,1);
        return getSqlDate(calendar.getTime());
    }
    /**
     * 获得某一日期的前一天
     * @param date java.util.Date类型
     * @return Date java.util.Date类型
     */
    public static Date getPreviousDate(Date date){
        Calendar calendar=Calendar.getInstance();
        calendar.setTime(date);
        int day=calendar.get(Calendar.DATE);
        calendar.set(Calendar.DATE,day-1);
        return getSqlDate(calendar.getTime());
    }
    /**
     * 获得某年某月最后一天的日期
     * @param year	年，可以为String或者int类型的
     * @param month	月，可以为String或者int类型的
     * @return Date	java.util.Date
     */
    public static<T,E> Date getLastDayOfMonth(T year,E month){
        int yy = getYear(year);
        int mm = getMonth(month);
        Calendar calendar=Calendar.getInstance();
        calendar.set(Calendar.YEAR,yy);
        calendar.set(Calendar.MONTH,mm);
        calendar.set(Calendar.DATE,1);
        return getPreviousDate(getSqlDate(calendar.getTime()));
    }
    /**
     * 获得给定日期的月份<br>
     * 如果参数为空则抛出运行时异常
     *
     * @param date
     * @return
     */
    public static Long getMonthOfDate(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空！");
        }
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        return (long) (cal.get(Calendar.MONTH) + 1);
    }
    /**
     * 获得给定日期的年份<br>
     * 如果参数为空则抛出运行时异常
     *
     * @param date
     * @return
     */
    public static Long getYearOfDate(Date date) {
        if (date == null) {
            throw new RuntimeException("日期不能为空！");
        }
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        return (long) (cal.get(Calendar.YEAR));
    }
    /**
     * 获得指定日后一月
     * @param date 指定日期
     * @return date 指定日期后一月
     */
    public static Date getNextMonth(Date date){
        Calendar calendar=Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MONTH,calendar.get(Calendar.MONTH)+1);
        return calendar.getTime();
    }
    /**
     * 获得指定日所在月最后一天的日期
     * @param date 指定日期
     * @return date 指定日期所在月最后一天的日期
     */
    public static Date getLastDateOfMonth(Date date){
        Calendar calendar=Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MONTH,calendar.get(Calendar.MONTH)+1);//月份加1
        calendar.set(Calendar.DATE,1-1);//所在月下一个月1号前一天,即月底日期
        return calendar.getTime();
    }
    /**
     * 获得给定日期当月的最后一天 如果参数为null，则抛出NullPointerException
     *
     * @param date
     * @return
     */
    public static Date getLastDayOfMonthByDate(Date date) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, 1);
        cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1);
        cal.add(Calendar.DATE, -1);
        return cal.getTime();
    }
    /**
     * 获取下个月1号
     * @author
     * @date 2022/9/23
     */
    public static Date getNextMonthFirDate(Date date){
        Calendar calendar=Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MONTH,calendar.get(Calendar.MONTH)+1);//月份加1
        calendar.set(Calendar.DATE,1);//所在月下一个月1号
        return calendar.getTime();
    }
    /**
     * 计算参数日期所在年的最后一天
     *
     * @param yearDate
     * @return
     */
    public static Date getLastDayOfYearDate(Date yearDate) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(yearDate);
        cal.set(Calendar.DATE, 1);
        cal.set(Calendar.MONTH, 0);
        cal.add(Calendar.YEAR, 1);
        cal.add(Calendar.DATE, -1);
        return cal.getTime();
    }

    /**
     * 获取当前时间的年月日时分秒字符串
     * @return
     */
    public static String getDateStr(){
        //使用Date
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(d);
    }

    /**
     *@author 贾真行
     *@Description 获取指定年份的所有周末
     *@Date 16:36 2022/10/19
     *@Param
     *@Return
     **/
    public static List<String> getYearWeek(String year){
        List<String> list = new ArrayList<>();
        Calendar c = Calendar.getInstance();
        c.set(Integer.parseInt(year), 0, 1);
        Calendar c2 = Calendar.getInstance();
        c2.set(Integer.parseInt(year) + 1, 0, 1);
        int count = 0;
        while (c.compareTo(c2) < 0) {
            if (c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                String data = c.get(Calendar.YEAR)+ "-";
                if (c.get(Calendar.MONTH) + 1 < 10){
                    data += "0"+(c.get(Calendar.MONTH) + 1) + "-"+(c.get(Calendar.DAY_OF_MONTH)<10?"0"+c.get(Calendar.DAY_OF_MONTH):c.get(Calendar.DAY_OF_MONTH));
                }else {
                    data += (c.get(Calendar.MONTH) + 1) + "-"+(c.get(Calendar.DAY_OF_MONTH)<10?"0"+c.get(Calendar.DAY_OF_MONTH):c.get(Calendar.DAY_OF_MONTH));
                }
                list.add(data);
            }
            // 日期+1
            c.add(Calendar.DATE, 1);
        }
        return list;
    }

    /**
     * @Description: 时间戳转字符串
     * @Author: 贾真行
     * @Date: 2022/11/29
     * @Time: 18:11
     * @Param:
     * @Return:
     */
    public static String timeStamp2Date(String seconds,String format) {
        if(seconds == null || seconds.isEmpty() || seconds.equals("null")){
            return "";
        }
        if(format == null || format.isEmpty()){
            format = "yyyy-MM-dd";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date(Long.valueOf(seconds+"000")));
    }

    /**
     * @Description: 银票专门的算法 把天数转换为年  //此处写死为与360比 如有变更再改
     * @Author: 贾真行
     * @Date: 2023/2/6
     * @Time: 15:40
     * @Param:
     * @Return:
     */
    public static double ypGetDayByYear(int day){
        if (day < 0){
            throw new RuntimeException("天数不能为空");
        }

        //得到年的倍数
        int a = day / 360;

        //剩余的天数
        int b = a == 0 ? day : day - 360 * a;

        if (b < 150){
            return a + 0.0d;
        }else if (b >= 180 && b < 210){
            return a + 0.5d;
        }else {
            return a + 1;
        }

    }
}
